package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.commom.exception.CustException;
import com.heima.commom.exception.CustomException;
import com.heima.common.constants.message.PublishArticleConstants;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.feigns.AdminFeign;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojo.WmNews;
import com.heima.model.wemedia.pojo.vo.ImagesAndText;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.stringtemplate.v4.ST;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author by jojo
 * @Date 2022/3/4
 * @Description
 */
@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {
    @Autowired
    private GreenImageScan greenImageScan;
    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private AdminFeign adminFeign;
    @Autowired
    private WmNewsService wmNewsService;
    @Value("${file.oss.web-site}")
    String webSite;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 自媒体文章审核
     *
     * @param id 自媒体文章id
     */
    @Override
    public void autoScanWmNews(Integer id) {
        //参数校验
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "文章id出错");
        }
        //用id查文章内容
        WmNews wmNews = wmNewsService.getById(id);
        //判断该文章存不存在
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "该文章数据已丢失");
        }
        //判断该文章状态是否是待审核状态(1)
        if (!wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "该文章不是待审核状态！！！");
        }
        //获取文本和图片的内容
        ImagesAndText imagesAndText = handleImagesAndText(wmNews);
        String text = imagesAndText.getText();
        List<String> images = imagesAndText.getImages();
        if (StringUtils.isNotBlank(text)) {
            //自定义DFA敏感词审核
            boolean flag = handleSensitive(text, wmNews);
            if (!flag) {
                log.info("文章内容中有敏感词，审核不通过！");
                CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "审核失败");
            }
            //阿里云审核 文本  block:2 审核不通过 pass:8 审核通过 review:3转交人工审核
            boolean textFlag = handleTextScan(text, wmNews);
            if (!textFlag) {
                log.info("文章内容中有敏感词，审核不通过！");
                CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "审核失败");
            }
        }
        //阿里云审核 图片 block:2 审核不通过 pass:8 审核通过 review:3转交人工审核
        if (CollectionUtils.isNotEmpty(images)) {
            boolean imagesFlag = handleImagesScan(images, wmNews);
            if (!imagesFlag) {
                log.info("图片违规，审核不通过");
                CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "审核失败");
            }
        }
        //审核成功，修改状态为8
        updateWmNewsStatusAndReason(wmNews, WmNews.Status.SUCCESS.getCode(), "审核成功");
        // 发布延时任务，用于发布文章
        //发布时间
        long publishTime = wmNews.getPublishTime().getTime();
        //当前时间
        long nowTime = System.currentTimeMillis();
        //相差时间
        long remainTime = publishTime - nowTime;
        //发布文章
        rabbitTemplate.convertAndSend(PublishArticleConstants.DELAY_DIRECT_EXCHANGE,
                PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY,
                wmNews.getId(),
                message -> {
                    message.getMessageProperties().setHeader("x-delay", remainTime <= 0 ? 0 : remainTime);
                    return message;
                }
        );
        log.info("自动审核发布文章通知MQ成功，文章id：{}",wmNews.getId());
    }

    /**
     * 阿里云审核 图片 block:2 审核不通过 pass:8 审核通过 review:3转交人工审核
     *
     * @param images
     * @param wmNews
     * @return
     */
    private boolean handleImagesScan(List<String> images, WmNews wmNews) {
        boolean flag = false;
        try {
            Map map = greenImageScan.imageUrlScan(images);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    updateWmNewsStatusAndReason(wmNews, WmNews.Status.FAIL.getCode(), "图片违规，审核失败。");
                    break;
                case "review":
                    updateWmNewsStatusAndReason(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "图片审核不确定，移交人工审核。");
                    break;
                case "pass":
                    flag = true;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            updateWmNewsStatusAndReason(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云审核调用失败，转为人工审核。");
        }
        return flag;
    }

    /**
     * 阿里云审核 文本 block:2 审核不通过 pass:8 审核通过 review:3转交人工审核
     *
     * @param text
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String text, WmNews wmNews) {
        boolean flag = false;
        try {
            //调用阿里云审核文本
            Map map = greenTextScan.greenTextScan(text);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    updateWmNewsStatusAndReason(wmNews, WmNews.Status.FAIL.getCode(), "文章内容包含违规信息，审核不通过");
                    break;
                case "review":
                    updateWmNewsStatusAndReason(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文章内容包含不确定信息，移交人工处理");
                    break;
                case "pass":
                    flag = true;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            updateWmNewsStatusAndReason(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云审核调用失败，转为人工审核。");
        }
        return flag;
    }

    /**
     * 抽取文章中所有文本内容和图片URL
     *
     * @param wmNews
     * @return
     */
    private ImagesAndText handleImagesAndText(WmNews wmNews) {
        String contentJSON = wmNews.getContent();
        //判断该文章内容是否为空
        if (StringUtils.isBlank(contentJSON)) {
            log.error("该文章的内容不存在");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "该文章的内容不存在！！");
        }
        List<Map> contentMaps = JSONArray.parseArray(contentJSON, Map.class);
        //抽取文章内容
        String collectText = contentMaps.stream()
                .filter(m -> "text".equals(m.get("type")))
                .map(m -> (String) m.get("value"))
                .collect(Collectors.joining("_jojo_"));
        //将文章标题和文本内容拼接到一起
        collectText = wmNews.getTitle() + "_jojo_" + collectText;
        //抽取图片URL路径
        List<String> imageList = contentMaps.stream()
                .filter(m -> WemediaConstants.WM_NEWS_TYPE_IMAGE.equals(m.get("type")))
                .map(m -> (String) m.get("value"))
                .collect(Collectors.toList());
        //将内容图片和封面图片拼接到一起
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            //用stream将,分割字符串得到String数组，拼接前缀
            List<String> images = Arrays.stream(wmNews.getImages().split(","))
                    .map(url -> webSite + url)
                    .collect(Collectors.toList());
            imageList.addAll(images);
        }
        //将内容图片和封面图片去重
        imageList = imageList.stream().distinct().collect(Collectors.toList());
        //封装
        ImagesAndText imagesAndText = new ImagesAndText();
        imagesAndText.setText(collectText);
        imagesAndText.setImages(imageList);
        return imagesAndText;
    }

    /**
     * DFA敏感词校验
     *
     * @param contentText 文本
     * @param wmNews      发布的文章
     */
    private boolean handleSensitive(String contentText, WmNews wmNews) {
        boolean flag = true;
        //检查文本内容是否存在
        if (StringUtils.isNotBlank(contentText)) {
            //远程调用查询敏感词列表
            ResponseResult<List<String>> list = adminFeign.findByList();
            //校验远程查询是否成功
            if (!list.checkCode()) {
                CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
            }
            //获取敏感词列表
            List<String> listSensitives = list.getData();
            //判断该敏感词列表是不是空
            if (CollectionUtils.isNotEmpty(listSensitives)) {
                //用DFA工具类审核内容是否有敏感词
                SensitiveWordUtil.initMap(listSensitives);
                Map<String, Integer> map = SensitiveWordUtil.matchWords(contentText);
                //如果包含敏感词 修改状态为2 设置原因
                if (CollectionUtils.isNotEmpty(map)) {
                    updateWmNewsStatusAndReason(wmNews, WmNews.Status.FAIL.getCode(), "该文章内容中包含敏感词：" + map);
                    flag = false;
                }
            }
        }
        return flag;
    }

    /**
     * 修改文章的状态和原因
     *
     * @param wmNews
     * @param code
     * @param s
     */
    private void updateWmNewsStatusAndReason(WmNews wmNews, short code, String s) {
        wmNews.setStatus(code);
        wmNews.setReason(s);
        wmNewsService.updateById(wmNews);
    }
}
